package com.fengpb.friday.conductor.common.metadata.workflow;

import com.fengpb.friday.conductor.common.metadata.Auditable;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.util.*;

public class WorkflowDef extends Auditable {

    @NotEmpty(message = "流程定义name不可为空")
    private String name;

    private String description;

    private int version = 1;

    @NotEmpty(message = "流程定义任务集合不可为空")
    private List<@Valid WorkflowTask> tasks = new LinkedList<>();

    private Map<String, Object> outputParameters = new HashMap<>();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public int getVersion() {
        return version;
    }

    public void setVersion(int version) {
        this.version = version;
    }

    public List<WorkflowTask> getTasks() {
        return tasks;
    }

    public void setTasks(List<WorkflowTask> tasks) {
        this.tasks = tasks;
    }

    public Map<String, Object> getOutputParameters() {
        return outputParameters;
    }

    public void setOutputParameters(Map<String, Object> outputParameters) {
        this.outputParameters = outputParameters;
    }

    public WorkflowTask getNextTask(String taskReferenceName) {
        WorkflowTask workflowTask = getTaskByRefName(taskReferenceName);
        if (workflowTask != null && TaskType.TERMINATE.name().equals(workflowTask.getType())) {
            return null;
        }

        Iterator<WorkflowTask> it = tasks.iterator();
        while(it.hasNext()) {
            WorkflowTask task = it.next();
            if (task.getTaskReferenceName().equals(taskReferenceName)) {
                break;
            }
            WorkflowTask nextTask = task.next(taskReferenceName, null);
            if(nextTask != null) {
                return nextTask;
            } else if (TaskType.DO_WHILE.name().equals(task.getType()) && !task.getTaskReferenceName().equals(taskReferenceName) && task.has(taskReferenceName)) {
                // If the task is child of Loop Task and at last position, return null.
                return null;
            }

            if(task.has(taskReferenceName)) {
                break;
            }
        }
        if(it.hasNext()){
            return it.next();
        }
        return null;
    }

    public WorkflowTask getTaskByRefName(String taskReferenceName){
        return collectTasks().stream()
                .filter(workflowTask -> workflowTask.getTaskReferenceName().equals(taskReferenceName))
                .findFirst()
                .orElse(null);
    }

    public List<WorkflowTask> collectTasks() {
        List<WorkflowTask> tasks = new LinkedList<>();
        for (WorkflowTask workflowTask : this.tasks) {
            tasks.addAll(workflowTask.collectTasks());
        }
        return tasks;
    }
}
